import { exec } from 'child_process';
import { promisify } from 'util';
import { file } from 'tmp-promise';
import * as fs from 'fs/promises';
import { logger } from '../utils/logger';
import { ApiError } from '../middleware/errorHandler';

const execAsync = promisify(exec);

// 代码分析结果接口
interface AnalysisResult {
  issues: Issue[];
  complexity: number;
  codeQuality: string; // "good", "average", "poor"
  suggestions: string[];
}

// 代码问题接口
interface Issue {
  line: number;
  column: number;
  severity: 'error' | 'warning' | 'info';
  message: string;
  ruleId?: string;
}

// 各语言分析工具配置
const analysisConfigs: { [key: string]: { tool: string; runCmd: (filename: string) => string; parseOutput: (output: string) => AnalysisResult } } = {
  javascript: {
    tool: 'eslint',
    runCmd: (filename) => `eslint --format json ${filename}`,
    parseOutput: parseEslintOutput,
  },
  typescript: {
    tool: 'eslint',
    runCmd: (filename) => `eslint --format json ${filename}`,
    parseOutput: parseEslintOutput,
  },
  python: {
    tool: 'pylint',
    runCmd: (filename) => `pylint --output-format=json ${filename}`,
    parseOutput: parsePylintOutput,
  },
  go: {
    tool: 'go vet',
    runCmd: (filename) => `go vet -json ${filename}`,
    parseOutput: parseGoVetOutput,
  },
};

/**
 * 分析代码质量
 * @param language 编程语言
 * @param code 代码内容
 * @returns 分析结果
 */
export async function analyzeCode(language: string, code: string): Promise<AnalysisResult> {
  // 检查语言是否支持
  if (!analysisConfigs[language]) {
    return {
      issues: [],
      complexity: 0,
      codeQuality: "unknown",
      suggestions: ["Language not supported for analysis"]
    };
  }

  try {
    // 创建临时文件
    const { path, cleanup } = await file({
      prefix: `analysis-`,
      postfix: `.${language === 'typescript' ? 'ts' : language === 'javascript' ? 'js' : language === 'python' ? 'py' : 'go'}`,
    });

    // 写入代码到临时文件
    await fs.writeFile(path, code);

    // 分析代码
    const config = analysisConfigs[language];
    const { stdout, stderr } = await execAsync(config.runCmd(path));
    
    // 清理临时文件
    await cleanup();

    // 解析输出
    if (stderr && !stdout) {
      logger.warn(`Analysis warning: ${stderr}`);
    }

    return config.parseOutput(stdout);
  } catch (error) {
    logger.error(`Code analysis error: ${error instanceof Error ? error.message : 'Unknown error'}`);
    
    return {
      issues: [],
      complexity: 0,
      codeQuality: "unknown",
      suggestions: ["Analysis failed due to an internal error"]
    };
  }
}

/**
 * 计算代码复杂度
 * @param code 代码内容
 * @returns 复杂度评分（0-100，越低越好）
 */
function calculateComplexity(issues: Issue[]): number {
  const errorCount = issues.filter(i => i.severity === 'error').length;
  const warningCount = issues.filter(i => i.severity === 'warning').length;
  
  // 简单的复杂度计算公式，可根据需要调整
  const complexity = Math.min(100, (errorCount * 10) + (warningCount * 3));
  
  return complexity;
}

/**
 * 根据问题数量评估代码质量
 */
function evaluateCodeQuality(complexity: number): string {
  if (complexity < 20) return "good";
  if (complexity < 50) return "average";
  return "poor";
}

/**
 * 生成改进建议
 */
function generateSuggestions(issues: Issue[]): string[] {
  const suggestions: string[] = [];
  
  // 根据最常见的问题类型生成建议
  const errorTypes = issues.map(i => i.ruleId || i.message).reduce((acc, curr) => {
    acc[curr] = (acc[curr] || 0) + 1;
    return acc;
  }, {} as Record<string, number>);
  
  // 获取最常见的3个问题
  const commonIssues = Object.entries(errorTypes)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 3)
    .map(([issue]) => issue);
  
  // 为每个常见问题生成建议
  commonIssues.forEach(issue => {
    const relatedIssue = issues.find(i => (i.ruleId === issue || i.message === issue));
    if (relatedIssue) {
      suggestions.push(`Fix "${relatedIssue.message}" issues to improve code quality`);
    }
  });
  
  // 添加一般性建议
  if (issues.length > 0) {
    suggestions.push("Follow language style guide to improve code consistency");
    suggestions.push("Add proper error handling to make code more robust");
  }
  
  return suggestions;
}

/**
 * 解析ESLint输出
 */
function parseEslintOutput(output: string): AnalysisResult {
  try {
    const eslintResult = JSON.parse(output);
    
    // 转换ESLint问题为标准格式
    const issues: Issue[] = [];
    
    if (Array.isArray(eslintResult) && eslintResult.length > 0) {
      eslintResult[0].messages.forEach((msg: any) => {
        issues.push({
          line: msg.line,
          column: msg.column,
          severity: msg.severity === 2 ? 'error' : msg.severity === 1 ? 'warning' : 'info',
          message: msg.message,
          ruleId: msg.ruleId
        });
      });
    }
    
    const complexity = calculateComplexity(issues);
    const codeQuality = evaluateCodeQuality(complexity);
    const suggestions = generateSuggestions(issues);
    
    return {
      issues,
      complexity,
      codeQuality,
      suggestions
    };
  } catch (error) {
    logger.error(`Error parsing ESLint output: ${error instanceof Error ? error.message : 'Unknown error'}`);
    return {
      issues: [],
      complexity: 0,
      codeQuality: "unknown",
      suggestions: ["Failed to parse analysis results"]
    };
  }
}

/**
 * 解析Pylint输出
 */
function parsePylintOutput(output: string): AnalysisResult {
  try {
    const pylintResult = JSON.parse(output);
    
    // 转换Pylint问题为标准格式
    const issues: Issue[] = pylintResult.map((msg: any) => ({
      line: msg.line,
      column: msg.column,
      severity: msg.type === 'error' ? 'error' : msg.type === 'warning' ? 'warning' : 'info',
      message: msg.message,
      ruleId: msg.symbol
    }));
    
    const complexity = calculateComplexity(issues);
    const codeQuality = evaluateCodeQuality(complexity);
    const suggestions = generateSuggestions(issues);
    
    return {
      issues,
      complexity,
      codeQuality,
      suggestions
    };
  } catch (error) {
    logger.error(`Error parsing Pylint output: ${error instanceof Error ? error.message : 'Unknown error'}`);
    return {
      issues: [],
      complexity: 0,
      codeQuality: "unknown",
      suggestions: ["Failed to parse analysis results"]
    };
  }
}

/**
 * 解析Go Vet输出
 */
function parseGoVetOutput(output: string): AnalysisResult {
  try {
    const goVetResult = output ? JSON.parse(output) : [];
    
    // 转换Go Vet问题为标准格式
    const issues: Issue[] = Array.isArray(goVetResult) ? goVetResult.map((msg: any) => ({
      line: msg.posn.line || 0,
      column: msg.posn.column || 0,
      severity: 'warning',
      message: msg.message || "Code issue detected",
      ruleId: msg.check || "unknown"
    })) : [];
    
    const complexity = calculateComplexity(issues);
    const codeQuality = evaluateCodeQuality(complexity);
    const suggestions = generateSuggestions(issues);
    
    return {
      issues,
      complexity,
      codeQuality,
      suggestions
    };
  } catch (error) {
    logger.error(`Error parsing Go Vet output: ${error instanceof Error ? error.message : 'Unknown error'}`);
    return {
      issues: [],
      complexity: 0,
      codeQuality: "unknown",
      suggestions: ["Failed to parse analysis results"]
    };
  }
} 